/**
 * 
 */
package com.loki.pdfSignature.tools;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Base64Utils;
import org.springframework.util.ResourceUtils;

import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.forms.fields.PdfButtonFormField;
import com.itextpdf.forms.fields.PdfFormField;
import com.itextpdf.forms.fields.PdfTextFormField;
import com.itextpdf.io.codec.Base64;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.color.Color;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.PdfSignatureAppearance.RenderingMode;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PdfSigner.CryptoStandard;
import com.itextpdf.signatures.PrivateKeySignature;

/**
 * @author loki
 *
 */
public class ContactSignatureProcessor {
	
	private ContactSignatureContext context;
	
	private PrivateKey privateKey;
	
	private Certificate[] trustChain;
	
	public ContactSignatureProcessor(ContactSignatureContext context) {
		this.context = context;
	}

	public byte[] process(){
		try {
			ByteArrayOutputStream out = fillForm();
			
			return signDetached(out.toByteArray());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 
	 * @param in
	 * @return
	 * @throws Exception
	 */
	private byte[] signDetached(byte[] penndingSignFile) throws Exception {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		PdfSigner signer = new PdfSigner(new PdfReader(new ByteArrayInputStream(penndingSignFile)), out, false);
		switch (CustomerType.get(context.getCustomerType())) {
			case PERSON:
				signer.setFieldName("customerSignature");
				signer.getSignatureAppearance()
					  .setSignatureGraphic(ImageDataFactory.create(context.getCustomerSignature()));
				break;
			case ORGA:
				signer.setFieldName("legalSignature");
				signer.getSignatureAppearance()
					  .setSignatureGraphic(ImageDataFactory.create(context.getLegalSignature()));
				break;
			default:
				return null;
		}
		
		signer.getSignatureAppearance()
			  .setReason(context.getSignReason())
			  .setContact(context.getEmail())
			  .setLocation(context.getAddress())
			  .setSignatureCreator("jupai")
			  .setRenderingMode(RenderingMode.GRAPHIC);
		
		// Creating the signature
		loadCerts();
	    IExternalSignature pks = new PrivateKeySignature(privateKey, "SHA-256",null);
	    IExternalDigest digest = new BouncyCastleDigest();
		signer.signDetached(digest, pks, trustChain, null, null, null, 0, CryptoStandard.CADES);
		return out.toByteArray();
	}
	
	/**
	 * 获取或生成签名需要的证书
	 * @throws Exception
	 */
	private void loadCerts() throws Exception {
		//TODO 从数据库获取
		String pass = "123456";
		String alias = "loki";
		String content = "/u3+7QAAAAIAAAABAAAAAQAEbG9raQAAAV0c1J+TAAAFAzCCBP8wDgYKKwYBBAEqAhEBAQUABIIE6+rb724W+eciMMzK9V8f/UGtzKLkIofsrSt7ktgkhMu3/mn7/OQCHws4SWhjQiSqjBt1ASakXtl3MMTRWc3dJ11CjGyfd96scntwIKaUAP6WtCj3p1iQUQwBUL6NLQd4aYAcYfCFwEyfU360pTBYORmhEom2GWjuxPWSF+XRTmNbr2ynFTw39D57l8cb+FegOIiKjKWM0Ho1HA5zbXwkZIqhuJj/i93HFXRpvRS3Faj3AFn1HcGDd89qj95zidl8A4n+DccAkiPYiFna85mQr/19duDOj1yR3f6NV8sZes1Gbi2jFnaRbKy4jlaflQuHNQGsUKj2sQ0Imp02HUqAJwgK/OOQsgIZtsyNWTGWiH1KeASyUkR2p6WO5tVHnEXffKowQSl78FsxWMTH1KXrdPTGZIQIWjgSx1hRPSa7Ssq6NKndgxR2ew3hJD/svUSa2TGsUZ7fRIo6UXFD25o52Ah04/lGvodLop3Td5VuZU0Jgw/fbm2sq5LiuN03X0BbuRhc6xesCN+rD3kMMmXhEOwG7mIHsxiqBkmF+Ydt5/zsfC4ChWTdrO9RFeCdlGaUIMyxbMEc95ZbvkHB7NkFhBlQkff9dd3TR3cUSQ1Vkv/D2RIiu+hKFSYjRZSAHACj8zPg8gL9rMrAI+R54Zoe+PdiRNlD7vAY8uqnYhqumSWBOzuPuGm0Na5KRWMMerhvEimHWKU5pIJiK3E9sxktVc6SGJf4fAQoIM/ha4NMVrAOHEBAFSZKFuxKEoUNC3ZHYkWp3ye5xSlAKqPDSj8pNbUnxDmJ3V4+Obze0Ssgxc/p/I8zUhDbfvJyqlweVPIUB1FZn1RbWIQe20//UNpVW48X/asrgfopZkS7AuiaStlv+BhXpTu1F5SiXYtrd8mlG1UITojfyY9muUkFVj6LT6aPrFY3KgeO4x3lREhOg4l/MmBWrTbez6AONrBt9YYmXM9aAP4Z4fULQRwMKf675BA7Ib+vQlmLzfve5/dlbD7Juh7KXrSyzforTO3bvFVSDZtYwKp3mKwo55GOXd2Rn4Rkh44c5lElF1/5PBdDmbrlKYF/8Juo6FSwL5AQC4kOpvPXu+w0ciRb3b8EpgW9HmDc5/9GpYheFHxxUicM38aHIpoTVjURT6QtertzxuWg5L7NsXXBr1Td339J8EnrnX7XiSQbc8aq6TkRq45aAlPr45dvv2yyeaDgSKLxyu6JqtSkAZ70E8/69j+9zTCzNwFFAOa6A5US96Y2JejtjnHkDkuKvg+AFrqCPEX+35JqsgUoPcc9O3kcNhPIG6wgZ6s8JEMyE3k/jUtkRoXQGrqkCwCj+M6IefDfjVoJknTDGa/P/hU1REEMkOLqa+cNsoHSRfMCH7jGwksyPCEN9RlXgMo12Rgq2nKeat6VZpl4HP8YXGZDst9xUHorYwBpFnHZwZ+toapbv4Ed874JEw0ooqc7XckrIw0EgX6pAXaA+BuTDtgZ4cR7d3GiNrUt/Gdp5CNKf3qk1ObdNIKWI02/Ba5/h0pHivhrT8YJcGE265mACn3k/wXmu+DqYprw3xhuyEro5Gd8jyPU+h1nxE+1POC1kmDaFjPGb8pVFGixxsx3raOhFe/m3vO39vREfT+ziLdVmwM2lqlCiRYhmKOVht8fcZCPNV2cAxfh8Uo2fFWq9C1TNo0g1N8nAAAAAgAFWC41MDkAAAP1MIID8TCCAtmgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBwDEkMCIGCSqGSIb3DQEJARYVYWRtaW5AZWhvdXNlY2hpbmEuY29tMSEwHwYDVQQDDBhpbnZlc3Rvci5qdXBhaW9ubGluZS5jb20xGTAXBgNVBAsMEE9ubGluZSBGaW5hbnRpYWwxOjA4BgNVBAoMMVNoYW5naGFpIEp1cGFpIE5ldGNvbSBTY2llbmNlIFRlY2hub2xvZ3kgQ28uLCBMdGQxETAPBgNVBAgMCFNoYW5naGFpMQswCQYDVQQGEwJDTjAeFw0xNzA3MDYxMTM0NDJaFw00OTA2MjkxMTM0NDJaMIG2MQswCQYDVQQGEwJDTjERMA8GA1UECAwIU2hhbmdoYWkxETAPBgNVBAcMCFNoYW5naGFpMTowOAYDVQQKDDFTaGFuZ2hhaSBKdXBhaSBOZXRjb20gU2NpZW5jZSBUZWNobm9sb2d5IENvLiwgTHRkMRkwFwYDVQQLDBBPbmxpbmUgRmluYW50aWFsMQ0wCwYDVQQDDARsb2tpMRswGQYJKoZIhvcNAQkBFgxsb2tpQDE2My5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCX2J1Zf8d65dO50f92Fp+9P0riKyHPW+UBYu06CClQ/dG5KQlCmTU6JL66H1gLsoU3om7PvUxqpln+ZSGKs7PO+DALaq0M50D1JayAYtuH3mbn6JOR9FZu4SUrW8zRxMe/L0uOhs0hRis4oSTnwo+ohw3/7VNo2KAViwgyATLJgniAPeyOv9nc9byWQHt0rYEPQhRsOCLpQH6WQoqyoddBhq5/UxozSC+PpKyZr5t6thHCHf3jOD6eAxna2XpBmjKk/B6yWMXLDlWfY8f9nfRkbndFrusJFxRoSYH1l90s6MkgbHksTm12lTKFk7b0WHG+5oTR0MSlp9yepJuUTrENAgMBAAEwDQYJKoZIhvcNAQELBQADggEBANE6u0gpV48YxWnMmFkdQy8p5rgTnRp4mN0ORRidbDS+3MYPsYwCj3Q2svTRWK5Z6zQa/3LWvqPV9QHwRwfHS1BseL0U2xIVtZ+guKYJBxvOls9c8NyY8tPipCvq59et9FJjyh47uT0C/Go02+DFU+AgeACfFW8huz2BoMAYmbTygFtpWDETX91C5fbyO68MgMLLz7ZeOtZlcg1CkCkjRJ8flNZDx5thoA8pxH3IA+Nk87ZjC5gJWWTyx5Yuqwp8JLtibdEtc/r1vMyDwUqDuHvI8LWGUlmZroeOCYjWATmYUua2KEZo5faOR8D/rpb2y8byagWlxD1yUo+ZJWIAr8wABVguNTA5AAAEWTCCBFUwggM9oAMCAQICCQDbRmOzJBeYpzANBgkqhkiG9w0BAQsFADCBwDELMAkGA1UEBhMCQ04xETAPBgNVBAgMCFNoYW5naGFpMTowOAYDVQQKDDFTaGFuZ2hhaSBKdXBhaSBOZXRjb20gU2NpZW5jZSBUZWNobm9sb2d5IENvLiwgTHRkMRkwFwYDVQQLDBBPbmxpbmUgRmluYW50aWFsMSEwHwYDVQQDDBhpbnZlc3Rvci5qdXBhaW9ubGluZS5jb20xJDAiBgkqhkiG9w0BCQEWFWFkbWluQGVob3VzZWNoaW5hLmNvbTAeFw0xNzA3MDYxMDAzNTlaFw0yMDA3MDUxMDAzNTlaMIHAMQswCQYDVQQGEwJDTjERMA8GA1UECAwIU2hhbmdoYWkxOjA4BgNVBAoMMVNoYW5naGFpIEp1cGFpIE5ldGNvbSBTY2llbmNlIFRlY2hub2xvZ3kgQ28uLCBMdGQxGTAXBgNVBAsMEE9ubGluZSBGaW5hbnRpYWwxITAfBgNVBAMMGGludmVzdG9yLmp1cGFpb25saW5lLmNvbTEkMCIGCSqGSIb3DQEJARYVYWRtaW5AZWhvdXNlY2hpbmEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7dAqBLg7oCFSK/E8cfF4PNQGfKThw3YrslHvk7qZw4g+Pfuj6bStJ7h+Um15DEgJtFiekt/Svk2InOCj4+FftvzZ/6OoNAFM1ziOfBFPZ5nL7P2GgUaatHwFUiWqU7Cx8yA6Qvz4eOgPSrF/nWxnQBji9+8WtjdUQ3hvR0fAmgt7S+2Lq9nxH+NVWL66ULyh7bYK7IjkE2k6XpcFAgyvHWMXo4puhJlFNPgZc6vPYJ5M9s7MQr62kUbUoyRmy9bO/Xti5MmGEchsJVnUKnaUpNDOB0FZk9r81KQAQUmutrsIAmiV7CK4ZsMFjLZE8wQ3qhCin6RHBHQVVj3WDx9TvQIDAQABo1AwTjAdBgNVHQ4EFgQUyIUoAAKYFSSZUtvf/TdzSL6CSkkwHwYDVR0jBBgwFoAUyIUoAAKYFSSZUtvf/TdzSL6CSkkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEA5VEcU+ML8sl3LsgYszcm0uZuSDkWlmP0yGHT4lYn6c5xFfEO/S/5sPuujFWPJk9FSkDevdWJuNh8xufU0kyjyTU7jPOzcAzys+y1cQjnfHH+PnmlW2HXhxaCMcpOvyGqHal2EMJ3RR8D9/avxXlHpGggldmE7CZdkUNhYH9qFYCIBXCdGkKo3tm0IEzgASHUKLOZc6eP1ESbfHEE5nhHyY9F+Z6ZN54O6Lsdui2BL5F+uehgFqYFxQxxHNhRrXZ+YjNdZbLEvMOx2HZO1U9ghLDDS5VvRVPb/nFXFCTPUMGuEM0XgdrCCIX7uwbdr4GedmDWV7vRYaVMf8V5LoEhZBImPMsT1jBCgQ8jAkq/AfceZz1C";
		
		KeyStore store=KeyStore.getInstance("JKS");
		store.load(new ByteArrayInputStream(Base64Utils.decodeFromString(content)),pass.toCharArray());
		privateKey = (PrivateKey) store.getKey(alias, pass.toCharArray());
		trustChain = store.getCertificateChain(alias);
	}

	/**
	 * 填充pdf表单
	 * @return
	 * @throws IOException
	 */
	private ByteArrayOutputStream fillForm() throws Exception {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		PdfDocument pdf = new PdfDocument(new PdfReader(new ByteArrayInputStream(context.getContact())),new PdfWriter(out));
		PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true);
		Map<String, PdfFormField> fields = form.getFormFields();
		
		if(CustomerType.get(context.getCustomerType()).equals(CustomerType.PERSON)){
			form.removeField("legalSignature");
			form.removeField("legalStamp");
		}else {
			form.removeField("customerSignature");
			if(context.getLegalStamp() != null){
				((PdfButtonFormField)fields.get("legalStamp")).setValue(Base64.encodeBytes(context.getLegalStamp()));
			}else{
				form.removeField("legalStamp");
			}
		}
		
		for (Entry<String, PdfFormField> entry : fields.entrySet()) {
			String key = entry.getKey();
			PdfFormField field = entry.getValue();
			try {
				if(key.endsWith("Signature")) continue;
				if(StringUtils.isNoneBlank(field.getValueAsString())) continue;
				form.partialFormFlattening(key);
				
				if(CertType.getByName(key) != null){
					if(context.getCerts().containsKey(key)){
						if(CertType.ORGA.containsKey(key)){
							field.setValue(context.getCerts().get(key));
						}else {
							field.setValue("Yes");
							//genertateCertNoField(pdf, form, fields,context.getCerts().get(key));
						}
					}
					continue;
				}
				
				field.setValue(BeanUtils.getProperty(context, key));
				
			} catch (Exception e) {
				field.setValue("");
			}
		}
		
		form.flattenFields();
		pdf.close();
		return out;
	}

	private void genertateCertNoField(PdfDocument pdf, PdfAcroForm form, Map<String, PdfFormField> fields, String cert) {
		PdfFormField certNo = fields.get("certNo");
		Rectangle rect = certNo.getPdfObject().getAsRectangle(PdfName.Rect);
		float x = rect.getX()+1;
		float y = rect.getY()+1;
		
		PdfFormField newCertNo = PdfFormField.createEmptyField(pdf);
		newCertNo.getPdfObject().putAll(certNo.getPdfObject());
		newCertNo.setPage(2);
		newCertNo.setFieldName("newCertNo");
		for (int i = 0; i < cert.length(); i++) {
			PdfTextFormField field = PdfTextFormField.createText(pdf, new Rectangle(x,y,15,15), "cert_"+x, String.valueOf(cert.charAt(i)));
			field.setFontSize(10f)
				 .setBorderWidth(0.1f)
				 .setBorderColor(Color.BLACK)
				 .setPage(2);
			newCertNo.addKid(field);
			x = x+16;
		}
		form.addField(newCertNo);
	}
	
}
